home *** CD-ROM | disk | FTP | other *** search
- /*============================================================================*\
- * ChooseTkl.c - mChooseMsg handler
- *
- * ChooseTkl.c contains just one enourmously long routine, DoChooseMsg. This
- * routine handles the display of a menu after it's been pulled down or popped up
- * and before it's erased.
- \*============================================================================*/
-
-
- /******************************************************************************\
- * Header Files
- \******************************************************************************/
-
- #include <Memory.h>
- #include <Menus.h>
- #include <Quickdraw.h>
- #include <Types.h>
- #include <Values.h>
- #include "ChooseTkl.h"
- #include "Concordia.h"
- #include "DrawTkl.h"
- #include "SizeTkl.h"
-
-
- /******************************************************************************\
- * Constants & Macros
- \******************************************************************************/
-
- #define noScroll ((short) 0) //Must not scroll
- #define upScroll ((short) 1) //Must scroll up
- #define downScroll ((short) 2) //Must scroll down
-
- /* System Globals */
- #define sgHuhRect *((Rect *) 0x09FA) //MenuSelect seems to need this
- #define sgMenuDisable *((long *) 0x0B54) //MenuDisable system global (IM-V)
-
-
- /******************************************************************************\
- * Function Prototypes
- \******************************************************************************/
-
- void RedrawItem (MenuHandle, short, Rect *, short);
-
-
- #pragma segment Main
- /******************************************************************************\
- * DoChooseMsg - Choose a menu item
- *
- * DoChooseMsg is an unbelievably long routine which processes the mChooseMsg
- * menu message for the menu specified by TheMenu. DoChooseMsg will determine
- * which menu items must be hilighted and unhighlighted, and will highlight and
- * unhighlight those items appropriately. If TheMenu has scroll arrows and the
- * location of the mouse (given in HitPt), is located in these scroll arrows,
- * DoChooseMsg will scroll the menu. DoChooseMsg will then draw any newly-
- * exposed menu items. When the end of TheMenu is reached while scrolling, the
- * scroll arrow at that end will be erased and the menu item behind it will be
- * drawn. If a scrolling menu was at one end when it's scrolled, DoChooseMsg
- * will draw a new scroll arrow at that end. The item number of the chosen item
- * is returned, or 0 if no item is chosen.
- *
- * Coding Notes
- * #A# - This loop calculates the item number and item rectangle of the item
- * being chosen, the item rectangle of the item that was chosen the last
- * time DoChooseMsg was called, and the sum of the heights of all of the
- * items in TheMenu. If no item is chosen or if the item is disabled, the
- * item number will be calculated as 0.
- * #B# - Read as: If the vertical coordinate in the TopMenuItem system global
- * doesn't coincide with the top of the menu rectangle, this menu has a top
- * scroll arrow.
- * #C# - Read as: If the vertical coordinate in the AtMenuBottom system global
- * doesn't coincide with the bottom of the menu rectangle, this menu has a
- * bottom scroll arrow.
- * #D# - If the menu has a top or bottom scroll arrow, set the clipping region so
- * that the scroll arrows won't be stomped on when items are hilighted and
- * unhilighted.
- * #E# - If we're scrolling and there's no scroll bar at the other end, it must
- * be drawn and the scroll rectangle adjusted for that.
- * #F# - If we've scrolled to an end of a menu, the scroll bar at that end must
- * be drawn over.
- * #G# - This loop draws the menu items that intersect with UpdateRect.
- * #H# - If we saved the clip region, we'd better restore it.
- * #I# - Side Effect: System globals TopMenuItem and AtMenuBottom are modified
- * here. Icky, Poo!
- * #J# - Set high word of MenuDisable system global to menu ID, and low word to
- * the item number. Yes folks, even if the item is disabled.
- * #K# - If the item is disabled, its item number will be the 2's complement of
- * whatever it should be.
- * #L# - Why do I have to do this? BEATS THE HELL OUT OF ME!
- * #M# - Even if the new item isn't hierarchical, it might still get stomped on
- * when a hierarchical menu is erased.
- * #N# - We don’t need the menuEnabled bit any more so get rid of it by shifting
- * it out. Then we have to set the high bit so that all items beyond the
- * 31st will be enabled. With arithmetic right shifting, this high bit
- * will be preserved.
- * #O# - If a hierarchical menu is up right at the top or bottom of the screen
- * and the user moves the mouse into the scroll area of the main menu, we
- * get a mChooseMsg with the hit point in the scroll area before the child
- * menu is brought down. That would cause DoChooseMsg to scroll the main
- * menu while the child menu is still up. Because the Menu Bar Definition
- * Procedure saves the bits behind the child menu and because the child
- * menu slightly overlaps the main menu, scrolling while the hierarchical
- * menu is up causes a little bit of garbage to appear on the screen. To
- * prevent this, the DoDrawMsg routine clears a field in the MBSaveLoc
- * record to 0. DoChooseMsg checks this field. If it’s set to 1, then
- * scrolling is done as usual. If it’s clear, then scrolling is supressed
- * to give the menu bar definition procedure some time to bring down the
- * hierarchical menu first.
- \******************************************************************************/
-
- short
- DoChooseMsg (TheMenu, MenuRect, HitPt, WhichItem)
- MenuHandle TheMenu; //=> Menu to choose from >>
- Rect *MenuRect; //-> Menu's rectangle in global coords >>
- Point HitPt; //Location of mouse in global coords >>
- short WhichItem; //Old chosen item >>
- {
- Str255 *ItemString; //-> Menu item's string
- ItemInfoPtr ItemInfo; //-> Item info record
- short ItemHeight; //Height of menu item in pixels
- Rect ItemRect; //Item's rectangle in screen coords
- short TotHeight; //Total height of menu in pixels
- Rect NewRect; //Rectangle of newly-chosen item in global coords
- short NewItem; //Item number of newly-chosen item
- Rect OldRect; //Rectangle of old chosen item in global coords
- short OldItem; //Item number of old chosen item
- short CurrItem; //Item number of item being processed
- short NewIsHier; //True if NewItem specifies hierarchical item
- short OldIsHier; //True if OldItem specifies hierarchical item
- short HasTopScrl; //True if menu has top scroll arrow
- short HasBotScrl; //True if menu has bottom scroll arrow
- short MustScrl; //Which direction must menu scroll, if any?
- short ScrollAmt; //Scrolling distance in pixels
- RgnHandle SavedClip; //=> Clip region before DoChooseMsg is called
- Rect MenuClip; //Menu's clip rectangle, if scroll icons present
- RgnHandle UpdateRgn; //=> Menu update region when scrolled
- Rect UpdateRect; //Menu update rectangle when scrolled
- long EnableFlags; //Menu's enable flags
- Boolean dontScroll; /* True if scrolling shouldn’t take place */
-
- EnableFlags = (unsigned long) (**TheMenu).enableFlags;
- if (EnableFlags & 1)
- {
- EnableFlags >>= (unsigned long) 1; //#N#
- EnableFlags |= 0x80000000;
- }
- else
- EnableFlags = (unsigned long) 0;
- SavedClip = (RgnHandle) null;
- NewRect = OldRect = *MenuRect;
- NewRect.top = NewRect.bottom = OldRect.top = OldRect.bottom = sgTopMenuItem;
- NewItem = 0;
- OldItem = 0;
- CurrItem = 1;
- TotHeight = 0;
- NewIsHier = OldIsHier = false;
- dontScroll = *((short *) ((*sgMBSaveLoc) + 16)) == 1; //#O#
- if (dontScroll)
- *((short *) ((*sgMBSaveLoc) + 16)) = 0;
- HLock ((Handle) TheMenu);
- ItemString = (Str255 *) (**TheMenu).menuData;
- ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
- while ((*ItemString) [0] != '\0') //#A#
- {
- ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString));
- ItemHeight = CalcItemHeight (*ItemString, ItemInfo);
- if (NewItem == 0)
- {
- NewRect.bottom = NewRect.top + ItemHeight;
- if (HitPt.v > NewRect.top && HitPt.v <= NewRect.bottom)
- {
- if (EnableFlags & 1) //#K#
- NewItem = CurrItem;
- else
- NewItem = -CurrItem;
- if (ItemInfo->kbdEquiv == (char) hMenuCmd)
- NewIsHier = true;
- }
- else
- NewRect.top += ItemHeight;
- }
- if (OldItem == 0)
- if (WhichItem == CurrItem)
- {
- OldRect.bottom = OldRect.top + ItemHeight;
- OldItem = WhichItem;
- if (ItemInfo->kbdEquiv == (char) hMenuCmd)
- OldIsHier = true;
- }
- else
- OldRect.top += ItemHeight;
- TotHeight += ItemHeight;
- CurrItem += 1;
- ItemString = (Str255 *) (ItemInfo + 1);
- EnableFlags >>= 1;
- }
- HUnlock ((Handle) TheMenu);
- if (HitPt.h < MenuRect->left || HitPt.h > MenuRect->right)
- NewItem = 0;
- MustScrl = noScroll;
- HasTopScrl = HasBotScrl = false;
- if (sgTopMenuItem != MenuRect->top) //#B#
- {
- HasTopScrl = true;
- if (HitPt.v < MenuRect->top + scrlIconHeight)
- {
- NewItem = 0;
- MustScrl = downScroll;
- }
- }
- if (sgAtMenuBottom != MenuRect->bottom) //#C#
- {
- HasBotScrl = true;
- if (HitPt.v > MenuRect->bottom - scrlIconHeight)
- {
- NewItem = 0;
- MustScrl = upScroll;
- }
- }
- if (HasBotScrl || HasTopScrl) //#D#
- {
- MenuClip = *MenuRect;
- if (HasBotScrl)
- MenuClip.bottom -= scrlIconHeight;
- if (HasTopScrl)
- MenuClip.top += scrlIconHeight;
- SavedClip = NewRgn ();
- GetClip (SavedClip);
- ClipRect (&MenuClip);
- }
- if (NewItem == 0)
- sgMenuDisable = 0L;
- else
- {
- sgMenuDisable = (**TheMenu).menuID << (BITS (long) / 2) | (NewItem > 0 ?
- NewItem : -NewItem); //#J# #K#
- if (NewItem < 0)
- NewItem = 0;
- }
- if (NewItem != 0 && NewIsHier) //#L#
- {
- sgHuhRect = NewRect;
- *((Rect *) ((*sgMBSaveLoc) + 6)) = NewRect;
- }
- if (NewItem != OldItem)
- {
- if (OldItem != 0)
- if (OldIsHier)
- RedrawItem (TheMenu, OldItem, &OldRect, false);
- else
- InvertRect (&OldRect);
- if (NewItem != 0)
- if (OldIsHier) //#M#
- RedrawItem (TheMenu, NewItem, &NewRect, true);
- else
- InvertRect (&NewRect);
- }
- if (!dontScroll && MustScrl && HitPt.h >= MenuRect->left && HitPt.h <=
- MenuRect->right)
- {
- if (MustScrl == upScroll)
- {
- if (! HasTopScrl) //#E#
- {
- DrawScroll (MenuRect, topScroll);
- MenuClip.top += scrlIconHeight;
- }
- ScrollAmt = MenuClip.bottom - HitPt.v;
- if (ScrollAmt < MenuRect->bottom - sgAtMenuBottom)
- ScrollAmt = MenuRect->bottom - sgAtMenuBottom;
- UpdateRgn = NewRgn ();
- ScrollRect (&MenuClip, 0, ScrollAmt, UpdateRgn);
- UpdateRect = (**UpdateRgn).rgnBBox;
- DisposeRgn (UpdateRgn);
- sgTopMenuItem += ScrollAmt; //#I#
- sgAtMenuBottom += ScrollAmt;
- if (sgAtMenuBottom == MenuRect->bottom) //#F#
- UpdateRect.bottom += scrlIconHeight;
- if (SavedClip == (RgnHandle) null)
- {
- SavedClip = NewRgn ();
- GetClip (SavedClip);
- }
- ClipRect (&UpdateRect);
- EraseRect (&UpdateRect);
- }
- else
- {
- if (! HasBotScrl) //#E#
- {
- DrawScroll (MenuRect, botScroll);
- MenuClip.bottom -= scrlIconHeight;
- }
- ScrollAmt = MenuClip.top - HitPt.v;
- if (ScrollAmt > MenuRect->top - sgTopMenuItem)
- ScrollAmt = MenuRect->top - sgTopMenuItem;
- UpdateRgn = NewRgn ();
- ScrollRect (&MenuClip, 0, ScrollAmt, UpdateRgn);
- UpdateRect = (**UpdateRgn).rgnBBox;
- DisposeRgn (UpdateRgn);
- sgTopMenuItem += ScrollAmt;
- sgAtMenuBottom += ScrollAmt;
- if (sgTopMenuItem == MenuRect->top) //#F#
- UpdateRect.top -= scrlIconHeight;
- if (SavedClip == (RgnHandle) null)
- {
- SavedClip = NewRgn ();
- GetClip (SavedClip);
- }
- ClipRect (&UpdateRect);
- EraseRect (&UpdateRect);
- }
- SetRect (&ItemRect, MenuRect->left, sgTopMenuItem, MenuRect->right,
- sgTopMenuItem);
- EnableFlags = (unsigned long) (**TheMenu).enableFlags;
- if (EnableFlags & 1)
- {
- EnableFlags >>= (unsigned long) 1;
- EnableFlags |= 0x80000000;
- }
- else
- EnableFlags = (unsigned long) 0;
- HLock ((Handle) TheMenu);
- ItemString = (Str255 *) (**TheMenu).menuData;
- ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
- while ((*ItemString) [0] != '\0') //#G#
- {
- ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize
- (*ItemString));
- ItemRect.bottom = ItemRect.top + CalcItemHeight (*ItemString,
- ItemInfo);
- if (ItemRect.top < UpdateRect.bottom && ItemRect.bottom >
- UpdateRect.top)
- DrawItem (*ItemString, ItemInfo, &ItemRect, EnableFlags & 1);
- EnableFlags >>= 1;
- ItemRect.top = ItemRect.bottom;
- ItemString = (Str255 *) (ItemInfo + 1);
- }
- HUnlock ((Handle) TheMenu);
- }
- if (SavedClip != (RgnHandle) null) //#H#
- {
- SetClip (SavedClip);
- DisposeRgn (SavedClip);
- }
- return NewItem;
- }
-
-
- #pragma segment Main
- /******************************************************************************\
- * RedrawItem - Redraw a menu item for hierarchical menus
- *
- * RedrawItem redraws a menu item that's been clobbered by a hierarchical menu.
- * The affected menu is specified by TheMenu. The item number of the menu item
- * to redraw is given in ItemNum, while the item's rectangle is given in
- * ItemRect. If the item is going to be selected, Select must be true so that
- * the item will be redrawn in inverse. Otherwise Select must be false so that
- * the item will be redrawn normally.
- \******************************************************************************/
-
- static void
- RedrawItem (TheMenu, ItemNum, ItemRect, Select)
- MenuHandle TheMenu; //=> Menu of life >>
- short ItemNum; //Item number of item to redraw >>
- Rect *ItemRect; //Rectangle of item in screen coords >>
- short Select; //True if item should be selected
- {
- Str255 *ItemString; //-> Menu item's string
- ItemInfoPtr ItemInfo; //-> Item info record
- short CurrItem; //Item number of item being checked
- TextStateRec TextState; //Current text modes, etc.
-
- CurrItem = 0;
- HLock ((Handle) TheMenu);
- ItemString = (Str255 *) (**TheMenu).menuData;
- ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
- while (ItemNum != CurrItem && (*ItemString) [0] != '\0')
- {
- ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize
- (*ItemString));
- CurrItem += 1;
- if (ItemNum == CurrItem)
- {
- GetTextState (&TextState);
- EraseRect (ItemRect);
- DrawItem (*ItemString, ItemInfo, ItemRect, true);
- if (Select)
- InvertRect (ItemRect);
- SetTextState (&TextState);
- }
- else
- ItemString = (Str255 *) (ItemInfo + 1);
- }
- HUnlock ((Handle) TheMenu);
- }
-